using System;
using System.Collections.Generic;
using System.Html;
using System.Runtime.CompilerServices;
using Awaiter;
using Nsb;
using Nsb.Classes;
using ThemeChain;
using Yoshi.Classes;
using jQueryApi;

namespace Yoshi.Fb
{
    [IgnoreNamespace]
    public class FbIdentity : RecordStore
    {

        private const string AppPath = "/yoshi/php/fb/";

        private const string FbScope =
            "publish_stream,read_friendlists,email,user_birthday,user_photos,user_about_me,user_notes";

        internal const string FbUrlHttp = "http://graph.facebook.com";
        private const string FbUrlHttps = "https://graph.facebook.com";

        private const int Limit = 5000;

        private static readonly string FbAuthUrl = AppPath +
                                                   (ThemeBase.IsLocalhost
                                                        ? "fb.authlcl.php"
                                                        : "fb.auth.php") + "?scope=" + FbScope;

        //private static readonly string FbAuthUrl = AppPath + "fb.auth.php" + "?scope=" + FbScope;

        public FbAuth FbBaseAuth;
        public FbUser FbBaseUser;
        private readonly Dictionary<string, object> _cache = new Dictionary<string, object>();

        /// <summary>
        /// Use for setting properties while chaining methods.
        /// </summary>
        /// <param name="name">property name</param>
        /// <param name="value">property value</param>
        /// <returns>this object</returns>
        // ReSharper disable UnusedMember.Global
        public FbIdentity SetProperty(string name, string value)
        // ReSharper restore UnusedMember.Global
        {
            Type.SetField(this, name, value);
            return this;
        }

        public bool Authenticated
        {
            get { return Script.IsValue(FbBaseUser); }
        }

        protected void FbAuthenticateAw(Await awp)
        {
            FbBaseAuth = GetAuthToken();

            jQueryAjaxOptions request = new jQueryAjaxOptions();

            FbLimitRequest fbLimitRequest = new FbLimitRequest();
            fbLimitRequest.access_token = FbBaseAuth.access_token;

            request.Url = FbUrlHttps + "/me";
            request.Type = "GET";
            request.DataType = "jsonp";
            request.Data = fbLimitRequest;

            request.Success =
                delegate(object fbo, string textStatus, jQueryXmlHttpRequest request1)
                {
                    try
                    {
                        OnErrorReauthenticateAw(awp, (FbObject) fbo);
                        FbBaseUser = Master.FbUser = new FbUser();
                        // ReSharper disable PossibleInvalidCastException
                        jQuery.Extend(true, FbBaseUser, (FbUser)fbo);
                        // ReSharper restore PossibleInvalidCastException
                        Master.Profile.Initialize(FbBaseUser.id);
                        Inform.Log(String.Format("request.Success : User: {0}", FbBaseUser.name));
                        awp.Done();
                    }
                    catch (Exception ex)
                    {
                        Inform.Log(String.Format("Facebook authentication failure: {0}", ex));
                        awp.Handle(new Exception(Exceptions.ServiceLoginFailure));
                    }
                };

            request.Error =
                delegate
                {
                    Inform.Error("Error sending Facebook authentication request");
                    awp.Abort();
                };

            jQuery.Ajax(request);
        }

        protected void Post(string id, Dictionary<string, object> values, string connection, FnDelegate1 fn)
        {
            jQueryAjaxOptions ajaxRequest = new jQueryAjaxOptions();

            //values["access_token"] = FbBaseAuth.access_token;

            ajaxRequest.Url = FbUrlHttps + "/" + id + (Script.IsValue(connection) ? "/" + connection : "") + "?access_token=" + FbBaseAuth.access_token;
            ajaxRequest.Type = "POST";
            ajaxRequest.DataType = "html";
            ajaxRequest.Data = values;

            ajaxRequest.Success =
                delegate(object fbo, string textStatus, jQueryXmlHttpRequest request1)
                {
                    if (Script.IsValue(fn))
                        fn(fbo);
                };

            ajaxRequest.Error =
                delegate(jQueryXmlHttpRequest request, string textStatus, Exception error) { Inform.Error(String.Format("Error posting to Facebook graph api : {0}", textStatus)); };

            jQuery.Ajax(ajaxRequest);
        }

        protected void DeleteById(string id, FnDelegate1 fn)
        {
            jQueryAjaxOptions ajaxRequest = new jQueryAjaxOptions();
            Dictionary<string, object> values = new Dictionary<string, object>();

            values["access_token"] = FbBaseAuth.access_token;
            values["method"] = "delete";

            ajaxRequest.Url = FbUrlHttps + "/" + id;
            ajaxRequest.Type = "POST";
            ajaxRequest.DataType = "json";
            ajaxRequest.Data = values;

            ajaxRequest.Success =
                delegate(object fbo, string textStatus, jQueryXmlHttpRequest request1)
                {
                    if (Script.IsValue(fn))
                        fn(fbo);
                };

            ajaxRequest.Error =
                delegate(jQueryXmlHttpRequest request, string textStatus, Exception error) { Inform.Error(String.Format("Error deleting in Facebook graph api : {0}", textStatus)); };

            jQuery.Ajax(ajaxRequest);
        }

        protected void Get(string id, string connection, FnDelegate1 fn)
        {
            jQueryAjaxOptions ajaxRequest = new jQueryAjaxOptions();
            Dictionary<string, object> values = new Dictionary<string, object>();

            values["access_token"] = FbBaseAuth.access_token;
            values["limit"] = Limit;

            ajaxRequest.Url = FbUrlHttps + "/" + id + (Script.IsValue(connection) ? "/" + connection : "");
            ajaxRequest.Type = "GET";
            ajaxRequest.DataType = "jsonp";
            ajaxRequest.Data = values;

            ajaxRequest.Success =
                delegate(object fbo, string textStatus, jQueryXmlHttpRequest request1) { if (Script.IsValue(fn)) fn(fbo); };

            ajaxRequest.Error =
                delegate(jQueryXmlHttpRequest request, string textStatus, Exception error) { Inform.Error(String.Format("Error getting from Facebook graph api : {0}", textStatus)); };

            jQuery.Ajax(ajaxRequest);
        }

        protected void GetCache(string id, string connection, FnDelegate1 fn)
        {
            string key = id + "/" + connection;
            if (_cache.ContainsKey(key))
            {
                if (Script.IsValue(fn))
                    fn(_cache[key]);
                return;
            }
            Get(id, connection,
                delegate(object fbo)
                {
                    _cache[key] = fbo;
                    if (Script.IsValue(fn))
                        fn(fbo);
                }
                );
        }

        private static void OnErrorReauthenticateAw(Await awp, FbObject fbo)
        {
            if (Script.IsValue(fbo))
            {
                if (Script.IsValue(fbo.error))
                {
                    if (fbo.error.type == "OAuthException")
                    {
                        Storage.SetLocal("EntryUrl", Window.Location.Href);
                        Window.Location.Href = Window.Location.Protocol + "//" + Window.Location.HostnameAndPort + "/" +
                                               FbAuthUrl;
                        awp.Abort();
                        throw new Exception("FBDone");
                    }
                    Inform.Error(fbo.error.message);
                    awp.Handle(new Exception("FBError"));
                }
            }
        }

        private static FbAuth GetAuthToken()
        {
            FbAuth auth = new FbAuth();
            string vars = Window.Location.Search.Substr(1);
            if (!String.IsNullOrEmpty(vars))
            {
                string[] pairs = vars.Split("&");
                foreach (string pair in pairs)
                {
                    string[] nvp = pair.Split("=");
                    string n = nvp[0];
                    string v = nvp[1];
                    switch (n)
                    {
                        case "access_token":
                            auth.access_token = v;
                            break;
                        case "expires":
                            int expires = Number.ParseInt(v) * 1000;
                            auth.expires = (new Date()).GetTime() + expires;
                            break;
                    }
                }
            }
            if (!Script.IsNullOrUndefined(auth.access_token))
            {
                Storage.SetLocal("FbAccessToken", auth);
                Inform.Log("access_token={0}", auth.access_token);
                Inform.Log("expires={0}", new Date(auth.expires));
                //string url = (string)Storage.GetLocal("EntryUrl");
                string url = Window.Location.Href.Split("?")[0];
                if (!String.IsNullOrEmpty(url))
                {
                    Window.Location.Href = url;
                    throw new Exception("FBDone");
                }
            }

            auth = (FbAuth)Storage.GetLocal("FbAccessToken");
            return Script.IsNullOrUndefined(auth) ? new FbAuth() : auth;
        }
    }
}